class Vue {
    constructor(options) {
        //保存vue配置
        this.$options = options;
        //保存data
        this.$data = options.data;
        //响应化处理
        this.observe(this.$data);
        new Compile(options.el, this);
        //钩子函数
        if (options.created) {
            options.created.call(this);
        }
    }
    observe(obj) {
        if (!obj || typeof obj !== 'object') {
            return
        }
        //观察data中每一个数据
        for (const key in obj) {
            this.defineReactive(obj, key, obj[key]);
            this.proxyData(key);
        }
    }
    defineReactive(obj, key, val) { //数据劫持，完成响应式
        //深层次遍历
        this.observe(key);
        let _val = val;
        //为data中的每个key创建dep实例
        const dep = new Dep();
        Object.defineProperty(obj, key, {
            get() {
                // 依赖收集
                Dep.target && dep.addDep(Dep.target);
                return _val
            },
            set(newVal) {
                if (newVal !== val) {
                    _val = newVal;
                    dep.notify();
                }
            }
        })
    }
    // 在vue根上定义属性代理data中的数据
    proxyData(key) {
        // this指的KVue实例
        Object.defineProperty(this, key, {
            get() {
                return this.$data[key];
            },
            set(newVal) {
                this.$data[key] = newVal;
            }
        });
    }
}
class Dep { //建立依赖类，
    constructor() {
        this.watchers = []
    }
    addDep(watcher) {
        this.watchers.push(watcher)
    }
    notify() {
        this.watchers.forEach(watcher => watcher.update())
    }
}
class Watcher { // 创建Watcher：保存data中数值和页面中的挂钩关系
    constructor(vm, key, cb) {
        // 创建实例时立刻将该实例指向Dep.target便于依赖收集
        this.vm = vm;
        this.key = key;
        this.cb = cb;

        //用来存放解析到插值或者指令及对应的vm实例
        Dep.target = this;
        this.vm[this.key];//触发依赖收集
        Dep.target = null;
    }
    // 更新
    update() {
        // console.log(this.key + "更新了！");
        this.cb.call(this.vm, this.vm[this.key])
    }
}